package com.pnnd.stream;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;

public class ReadWriteHeapMemorySegment extends RandomAccessHeap {


    private static final int DEFAULT_PAGE_COUNT = 10;

    ReadWriteHeapMemorySegment(int pageCnt, Object owner) {
        super(pageCnt, owner);
    }

    ReadWriteHeapMemorySegment(Object owner) {
        super(DEFAULT_PAGE_COUNT, owner);
    }

    @Override
    public ByteBuffer wrap(int offset, int length) {

        if(this.offset < offset+length){
            throw new IndexOutOfBoundsException();
        }

        return super.wrap(offset,length);
    }

    @Override
    public byte get(int index) {

        if(this.offset < index){
            throw new IndexOutOfBoundsException();
        }

        return super.get(index);
    }

    @Override
    public void put(int index, byte b) {
        if(this.offset < index){
            throw new IndexOutOfBoundsException();
        }

        this.heapMemory[index] = b;

        if(index == this.offset){
            this.offset += 1;
        }
    }

    @Override
    public void get(int index, byte[] dst) {
        if(this.offset < index){
            throw new IndexOutOfBoundsException();
        }

        this.get(index,dst,0,Math.min(dst.length,this.offset - index));
    }

    @Override
    public void put(int index, byte[] src) {
        if(this.offset < index){
            throw new IndexOutOfBoundsException();
        }

        super.put(index,src);

        this.offset = Math.max(src.length+index,this.offset);
    }

    @Override
    public void get(int index, byte[] dst, int offset, int length) {
        if(this.offset < index){
            throw new IndexOutOfBoundsException();
        }

        this.get(index,dst,offset,Math.min(dst.length,this.offset - index));
    }

    @Override
    public void put(int index, byte[] src, int offset, int length) {

        if(this.offset < index || index < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.put(index,src,offset,length);

        this.offset = Math.max(src.length+index,this.offset);
    }

    @Override
    public boolean getBoolean(int index) {

        if(this.offset < index || index < this.address){
            throw new IndexOutOfBoundsException();
        }

        return super.getBoolean(index);
    }

    @Override
    public void putBoolean(int index, boolean value) {
        if(this.offset < index || index < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.putBoolean(index,value);

        if(index == this.offset){
            this.offset += 1;
        }
    }

    @Override
    public void get(DataOutput out, int offset, int length) throws IOException {
        if(this.offset < offset || offset < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.get(out,offset,Math.min(length,this.offset - offset));
    }

    @Override
    public void put(DataInput in, int offset, int length) throws IOException {
        if(this.offset < offset || offset < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.put(in,offset,length);

        this.offset = Math.max(offset+length,this.offset);
    }

    @Override
    public void get(int offset, ByteBuffer target, int numBytes) {
        if(this.offset < offset || offset < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.get(offset,target,numBytes);
    }

    @Override
    public void put(int offset, ByteBuffer source, int numBytes) {
        if(this.offset < offset || offset < this.address){
            throw new IndexOutOfBoundsException();
        }

        super.put(offset,source,numBytes);

        this.offset = Math.max(offset+numBytes,this.offset);
    }

    @Override
    public long end() {
        return this.addressLimit;
    }

    @Override
    public long start() {
        return this.address;
    }

    @Override
    public int physicsPageNum() {
        return this.pageCnt;
    }

    @Override
    public long offset() {
        return this.offset;
    }

    @Override
    public boolean hasMore() {
        return super.hasMore();
    }

    @Override
    public boolean canWrote(int size) {
        return super.canWrote(size);
    }
}
